#include "listopt.h"
#include <logbase.h>

static int nodeInsertNext(struct list_node *nownode, struct list_node *innode)
{
    if (!nownode || !innode)
    {
        logerrorc("");
        return -1;
    }
    if (nownode->nextn)
    {
        nownode->nextn->frontn = innode;
    }
    innode->nextn = nownode->nextn;
    innode->frontn = nownode;
    nownode->nextn = innode;
    return 0;
}
static int nodeInsertFront(struct list_node *nownode, struct list_node *innode)
{
    if (!nownode || !innode)
    {
        logerrorc("");
        return -1;
    }
    if (nownode->frontn)
    {
        nownode->frontn->nextn = innode;
    }
    innode->frontn = nownode->frontn;
    innode->nextn = nownode;
    nownode->frontn = innode;
    return 0;
}
static int nodeDelete(struct list_node *deletenode)
{
    if (!deletenode)
    {
        logerrorc("");
        return -1;
    }
    if (deletenode->frontn)
    {
        deletenode->frontn->nextn = deletenode->nextn;
    }
    if (deletenode->nextn)
    {
        deletenode->nextn->frontn = deletenode->frontn;
    }
    return 0;
}

int listRootInit(struct list_node_root *listroot)
{
    if (!listroot)
    {
        logerrorc("");
        return -1;
    }
    listroot->begin = NULL;
    listroot->end = NULL;
    listroot->nodesize = 0;
    pthread_mutex_init(&listroot->listlock, NULL);
    return 0;
}
int listRootFree(struct list_node_root *listroot)
{
    if (!listroot)
    {
        logerrorc("");
        return -1;
    }
    if (listroot->nodesize > 0)
    {
        logwarnc("free fail, list has data, size=%d", listroot->nodesize);
        return -1;
    }
    pthread_mutex_destroy(&listroot->listlock);
    return 0;
}
static int listRootPushback(struct list_node_root *listroot, struct list_node *innode)
{
    if (!listroot)
    {
        logerrorc("");
        return -1;
    }
    innode->frontn = innode->nextn = NULL;
    pthread_mutex_lock(&listroot->listlock);
    if (listroot->end == NULL)
    {
        if (listroot->begin != NULL)
        {
            logerrorc("end and begin mast all NULL or all have data");
        }
        listroot->begin = listroot->end = innode;
    }
    else
    {
        if (listroot->begin == NULL)
        {
            logerrorc("end and begin mast all NULL or all have data");
        }
        nodeInsertNext(listroot->end, innode);
        listroot->end = innode;
    }
    listroot->nodesize++;
    pthread_mutex_unlock(&listroot->listlock);
    return 1;
}
static int listRootPushfront(struct list_node_root *listroot, struct list_node *innode)
{
    if (!listroot)
    {
        logerrorc("");
        return -1;
    }
    innode->frontn = innode->nextn = NULL;
    pthread_mutex_lock(&listroot->listlock);
    if (listroot->begin == NULL)
    {
        if (listroot->end != NULL)
        {
            logerrorc("end and begin mast all NULL or all have data");
        }
        listroot->begin = listroot->end = innode;
    }
    else
    {
        if (listroot->end == NULL)
        {
            logerrorc("end and begin mast all NULL or all have data");
        }
        nodeInsertFront(listroot->begin, innode);
        listroot->begin = innode;
    }
    listroot->nodesize++;
    pthread_mutex_unlock(&listroot->listlock);
    return 1;
}
static int listRootPopback(struct list_node_root *listroot, struct list_node **outnode)
{
    if (!listroot || !outnode)
    {
        logerrorc("");
        return -1;
    }
    int tmpflag = 0;
    pthread_mutex_lock(&listroot->listlock);
    outnode[0] = listroot->end;
    if (listroot->end != NULL)
    {
        if (listroot->begin == NULL)
        {
            logerrorc("end and begin mast all NULL or all have data");
        }
        struct list_node *tmpnode = listroot->end->frontn;
        nodeDelete(listroot->end);
        listroot->end = tmpnode;
        listroot->nodesize--;
        tmpflag = 1;
    }
    if (listroot->end == NULL)
    {
        listroot->begin = listroot->end;
        if (listroot->nodesize != 0)
        {
            logerrorc("%d", listroot->nodesize);
        }
        listroot->nodesize = 0;
    }
    pthread_mutex_unlock(&listroot->listlock);
    return tmpflag;
}
static int listRootPopfront(struct list_node_root *listroot, struct list_node **outnode)
{
    if (!listroot || !outnode)
    {
        logerrorc("");
        return -1;
    }
    int tmpflag = 0;
    pthread_mutex_lock(&listroot->listlock);
    outnode[0] = listroot->begin;
    if (listroot->begin != NULL)
    {
        if (listroot->end == NULL)
        {
            logerrorc("end and begin mast all NULL or all have data");
        }
        struct list_node *tmpnode = listroot->begin->nextn;
        nodeDelete(listroot->begin);
        listroot->begin = tmpnode;
        listroot->nodesize--;
        tmpflag = 1;
    }

    if (listroot->begin == NULL)
    {
        listroot->end = listroot->begin;
        if (listroot->nodesize != 0)
        {
            logerrorc("%d", listroot->nodesize);
        }
        listroot->nodesize = 0;
    }
    pthread_mutex_unlock(&listroot->listlock);
    return tmpflag;
}
int listRootSize(struct list_node_root *listroot)
{
    if (!listroot)
    {
        logerrorc("");
        return -1;
    }
    return listroot->nodesize;
}

// 为用户节点分配空间，需要释放。如果是基础类型，不需要用户自己的空间userValueSize=0即可。
struct listUsrNdStct *listUsrMlcSpc(uint32_t usertype, uint32_t userValueSize)
{
    if (usertype < listValueTypeUser)
    {
        userValueSize = 0;
    }
    // 如果用户自定义空间，则会多出8字节损失。
    struct listUsrNdStct *tmpuser = malloc(sizeof(struct listUsrNdStct) + userValueSize);
    if (!tmpuser)
    {
        logerrorc("malloc error");
        return NULL;
    }
    tmpuser->valtype = usertype;
    tmpuser->valsize = userValueSize;
    return tmpuser;
}
struct listUsrNdStct *listUsrMlcI32(int32_t setVal)
{
    struct listUsrNdStct *tmpNode = listUsrMlcSpc(listValueTypeInt, 0);
    if(!tmpNode)
    {
        return tmpNode;
    }
    tmpNode->valint = setVal;
    return tmpNode;
}
struct listUsrNdStct *listUsrMlcU32(uint32_t setVal)
{
    struct listUsrNdStct *tmpNode = listUsrMlcSpc(listValueTypeU32, 0);
    if(!tmpNode)
    {
        return tmpNode;
    }
    tmpNode->valuint = setVal;
    return tmpNode;
}
struct listUsrNdStct *listUsrMlcI64(int64_t setVal)
{
    struct listUsrNdStct *tmpNode = listUsrMlcSpc(listValueTypeS64, 0);
    if(!tmpNode)
    {
        return tmpNode;
    }
    tmpNode->valint64 = setVal;
    return tmpNode;
}
struct listUsrNdStct *listUsrMlcU64(uint64_t setVal)
{
    struct listUsrNdStct *tmpNode = listUsrMlcSpc(listValueTypeU64, 0);
    if(!tmpNode)
    {
        return tmpNode;
    }
    tmpNode->valuint64 = setVal;
    return tmpNode;
}
struct listUsrNdStct *listUsrMlcFloat(float setVal)
{
    struct listUsrNdStct *tmpNode = listUsrMlcSpc(listValueTypeFloat, 0);
    if(!tmpNode)
    {
        return tmpNode;
    }
    tmpNode->valfloat = setVal;
    return tmpNode;
}
struct listUsrNdStct *listUsrMlcDouble(double setVal)
{
    struct listUsrNdStct *tmpNode = listUsrMlcSpc(listValueTypeDouble, 0);
    if(!tmpNode)
    {
        return tmpNode;
    }
    tmpNode->valdouble = setVal;
    return tmpNode;
}
// struct listUsrNdStct *listUsrMlcIstI32(struct list_node_root *listroot, int32_t setVal)
// {
//     struct listUsrNdStct *tmpuser = listUsrMlcI32(setVal);
//     if (!tmpuser)
//     {
//         logerrorc("malloc error");
//         return NULL;
//     }
//     listRootPushback(listroot, tmpuser);
//     return tmpuser;
// }
// struct listUsrNdStct *listUsrMlcIstU32(struct list_node_root *listroot, uint32_t setVal)
// {
//     struct listUsrNdStct *tmpuser = listUsrMlcU32(setVal);
//     if (!tmpuser)
//     {
//         logerrorc("malloc error");
//         return NULL;
//     }
//     listRootPushback(listroot, tmpuser);
//     return tmpuser;
// }
// struct listUsrNdStct *listUsrMlcIstI64(struct list_node_root *listroot, int64_t setVal)
// {
//     struct listUsrNdStct *tmpuser = listUsrMlcI64(setVal);
//     if (!tmpuser)
//     {
//         logerrorc("malloc error");
//         return NULL;
//     }
//     listRootPushback(listroot, tmpuser);
//     return tmpuser;
// }
// struct listUsrNdStct *listUsrMlcIstU64(struct list_node_root *listroot, uint64_t setVal)
// {
//     struct listUsrNdStct *tmpuser = listUsrMlcU64(setVal);
//     if (!tmpuser)
//     {
//         logerrorc("malloc error");
//         return NULL;
//     }
//     listRootPushback(listroot, tmpuser);
//     return tmpuser;
// }
// struct listUsrNdStct *listUsrMlcIstFloat(struct list_node_root *listroot, float setVal)
// {
//     struct listUsrNdStct *tmpuser = listUsrMlcFloat(setVal);
//     if (!tmpuser)
//     {
//         logerrorc("malloc error");
//         return NULL;
//     }
//     listRootPushback(listroot, tmpuser);
//     return tmpuser;
// }
// struct listUsrNdStct *listUsrMlcIstDouble(struct list_node_root *listroot, double setVal)
// {
//     struct listUsrNdStct *tmpuser = listUsrMlcDouble(setVal);
//     if (!tmpuser)
//     {
//         logerrorc("malloc error");
//         return NULL;
//     }
//     listRootPushback(listroot, tmpuser);
//     return tmpuser;
// }
int listUsrPushNd(struct list_node_root *listroot, struct listUsrNdStct *unode, int optbackflag)
{
    if (!listroot || !unode)
    {
        logerrorc("");
        return -1;
    }
    if (optbackflag)
    {
        return listRootPushback(listroot, &unode->node);
    }
    else
    {
        return listRootPushfront(listroot, &unode->node);
    }
}
int listUsrPushBack(struct list_node_root *listroot, struct listUsrNdStct *unode)
{
    return listUsrPushNd(listroot, unode, 1);
}
int listUsrPushFront(struct list_node_root *listroot, struct listUsrNdStct *unode)
{
    return listUsrPushNd(listroot, unode, 0);
}
struct listUsrNdStct *listUsrPopNd(struct list_node_root *listroot, int optbackflag)
{
    if (!listroot)
    {
        logerrorc("");
        return NULL;
    }
    struct list_node *tempnode;
    if (optbackflag)
    {
        listRootPopback(listroot, &tempnode);
    }
    else
    {
        listRootPopfront(listroot, &tempnode);
    }
    return (struct listUsrNdStct *)tempnode;
}
struct listUsrNdStct *listUsrPopBack(struct list_node_root *listroot)
{
    return listUsrPopNd(listroot, 1);
}
struct listUsrNdStct *listUsrPopFront(struct list_node_root *listroot)
{
    return listUsrPopNd(listroot, 0);
}
// struct listUsrNdStct *mallocUserNodeAndPush(struct list_node_root *listroot, uint32_t usertype, void *userdata,
//                                               uint32_t datasize, int backflag)
// {
//     struct listUsrNdStct *tmpuser = listUsrMlcSpc(usertype, datasize);
//     if (!tmpuser)
//     {
//         logerrorc("malloc error");
//         return NULL;
//     }
//     if (usertype < listValueTypeUser)
//     {
//         tmpuser->valcommon = userdata;
//     }
//     else
//     {
//         memcpy(tmpuser->valuser, userdata, datasize);
//     }
//     listUsrPushNd(listroot, tmpuser, backflag);
//     return tmpuser;
// }